package com.it.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.it.reggie.common.BaseContext;
import com.it.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//检查用户是否已经完成登录
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")//urlPatterns拦截那些（/*所有）请求路径
@Slf4j//通过日志的方式进行输出
public class LoginChatFilter implements Filter {
    //路径匹配器，支持通配符
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();//专门用来进行路径比较，是spring-core核心包提供的类，路径匹配器
//声明了一个名为‘PATH_MATCHER’的公共静态final‘AntPathMatcher’对象。‘PATH_MATCHER’对象被声明为常量，这意味着它一旦被初始化就不能被修改。
// 这是由'final'关键字表示的。
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;//request请求对象，想要输出request.getURI,需要先强制转换类型
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //1.获取本次请求的URI
        String requestURI = request.getRequestURI();
        log.info("拦截到请求：{}",requestURI);
        //2.判断本次请求是否需要处理（不登陆也能访问到的路径）
        String[] urls = new String[]{//请求的路径是否是在里面，如果是在里面，不需处理，后面封装一个check来判断
                "/employee/login",//点的是登录按钮，不用处理直接放行
                "/employee/logout",
                "/backend/**", //backend下的都是静态资源，不用处理直接放行
                "/front/**",
                "/common/**",//不登陆也可以正常访问CommonController.java里的upload方法了
                "/user/sendMsg",//移动端发送短信
                "/user/login",//移动端登录//让手机端用户能够完成登录
                //访问swagger框架生成的接口文档(运行之后访问http://localhost:8080/doc.html#/home)时的请求路径：
                "/doc.html",
                "/webjars/**",
                "/swagger-resources",
                "/v2/api-docs"

        };//不需要处理的请求放过去

        boolean check = check(urls,requestURI);//调用check方法//requestURI是本次请求的url

        //3.如果不需要处理（check=true时），则直接放行
        if(check){
//‘request’参数表示HTTP请求对象，其中包含请求方法、头、参数和主体等信息。
//“response”参数表示HTTP响应对象，该对象用于将响应发送回客户端。
            log.info("本次请求{}不需要处理",requestURI);
            filterChain.doFilter(request,response);
//在“FilterChain”对象上调用“doFilter”方法。此方法通常用于Java Web应用程序中，
//以在到达目标servlet或JSP页面之前通过一系列过滤器传递HTTP请求和响应对象。
            return;//放行之后，后面的代码没有必要执行了
        }


        //4-1.判断登录状态，如果已登录，则直接放行
        //从session里获取登录用户，如果能获取，则说明已经登录
        if(request.getSession().getAttribute("employee")!=null){
            log.info("用户已登录，用户Id为：{}",request.getSession().getAttribute("employee"));
            //登录成功之后，往request里的Session里存了一个employee作为key,而value对应的是emp.getId()的值(EmployeeController.java里的68行)
//已经登录就可以取出来了
            Long empId = (Long) request.getSession().getAttribute("employee");
            BaseContext.setCurrentId(empId);//在此设置当前登录用户id,在MyMetaObjecthandler.java里，获取getCurrentId()

//            long id = Thread.currentThread().getId();
//            log.info("当前线程id为：{}",id);

            filterChain.doFilter(request,response);//？？？？
            return;
        };//登陆时放进去的是employee，现在尝试着取出来

        //4-2.判断(移动端用户)登录状态，如果已登录，则直接放行
        //从session里获取登录用户，如果能获取，则说明已经登录
        if(request.getSession().getAttribute("user")!=null){
            log.info("（移动端）用户已登录，用户Id为：{}",request.getSession().getAttribute("user"));
            //登录成功之后，往request里的Session里存了一个user作为key,而value对应的是emp.getId()的值(EmployeeController.java里的68行)
//已经登录就可以取出来了
            Long userId = (Long) request.getSession().getAttribute("user");//在UserController的login里登陆成功之后存了user的id
            BaseContext.setCurrentId(userId);//在此设置当前登录用户id,在MyMetaObjecthandler.java里，获取getCurrentId()
            filterChain.doFilter(request,response);//？？？？
            return;
        };//登陆时放进去的是user，现在尝试着取出来

        log.info("用户未登录");
        //5.如果未登录则返回未登录结果，通过输出流方式向客户端页面响应数据//
        // 例如，检测到未登录，直接访问upload.html,浏览器检查响应在Response的{"code":0,"map":{},"msg":"NOTLOGIN"}
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));//把R对象转成json,然后通过输出流写回去，怎么写回去(response充当中介)????
//getWriter()方法返回一个PrintWriter对象(这是一个打印输出流)，该对象可用于向客户端发送字符文本。在这种情况下，‘write()’的方法用于编写JSON响应。
//NOTLOGIN来自于resources里的front/backend里的js里的request.js里的54/47行的第二个条件里的（res.data.code/msg===）
        return;
       // log.info("拦截到请求：{}",request.getRequestURI());//{}表示一个占位符, ","后面跟一个参数，这个参数就会输出到{}这个位置
        //放行
        //filterChain.doFilter(request,response);
    }//想要生效，需要在启动类上加一个注解@ServletComponentScan,他才会去扫描@WebFilter()注解，从而把过滤器创建出来



    //路径匹配，检查本次请求是否需要放行
    public boolean check(String[] urls, String requestURI){
        for(String url : urls){//遍历urls里的一个一个可放行路径url，看看本次请求的url是否与这里面的某一项可放行路径匹配，匹配到就放行
            boolean match = PATH_MATCHER.match(url, requestURI);//PATH_MATCHER(内部封装了match方法)在开头定义过了
            if(match){
                return true;//匹配上了
            }
        }
        return false;//全都循环完了，也没匹配上
    }
}
